
//***************************************************************************
//                           ColUtilsOpenSG
//***************************************************************************
//  Copyright (C):
//***************************************************************************

#ifndef ColUtilsOpenSG_H
#define ColUtilsOpenSG_H
#if defined(__sgi) || defined(_WIN32)
#pragma once
#endif

//---------------------------------------------------------------------------
//  Includes
//---------------------------------------------------------------------------

#include <math.h>

#include <OpenSG/OSGConfig.h>
#include <OpenSG/OSGBaseTypes.h>
#include <OpenSG/OSGBaseFunctions.h>
#include <OpenSG/OSGVector.h>
#include <OpenSG/OSGMatrix.h>
#include <OpenSG/OSGGeometry.h>
#include <OpenSG/OSGGeoProperty.h>
#include <OpenSG/OSGQuaternion.h>
#include <OpenSG/OSGGeoFunctions.h>
#include <OpenSG/OSGGeometry.h>
#include <OpenSG/OSGGeoProperty.h>
#include <OpenSG/OSGPrimitiveIterator.h>
#include <OpenSG/OSGFaceIterator.h>
#include <OpenSG/OSGTriangleIterator.h>

#include <col_import_export.h>
#include <ColTopology.h>

/// Collision detection namespace
namespace col {

using namespace std;
using osg::Vec3f;
using osg::Pnt3f;

/**  Compare points by angle
 *
 * @return
 *   True if point[i1] < point[i2] compared by angle, flse otherwise.
 *
 * Two points are connected with a "center" by a line each,
 * then the angle between those two lines and the @c x axis are computed,
 * and those are compared.
 * This functor is meant as a Binary Predicate for @c sort().
 *
 * Angles are in [0,360). No trigonometric function are evaluated,
 * and if the two points are in different quadrants, then only comparisons
 * are made, i.e.
 *                /  quadrant(p1) < quadrant(p2),   p1,p2 in different qu's
 *    p1 < p2 <=> |
 *                \  p1_y/p1_x < p2_y/p2_x      ,   p1,p2 in same quadrant
 *
 * @pre
 *   @c x, @c y, and @c point,npoints are set.
 *
 * @implementation
 *   The functor could return -1/0/+1 for less-than/euqal/greater-than.
 *   The original of this function is opyCompPointsByAngle in Y.
 **/

struct COL_EXPORTIMPORT lessByAngle : public binary_function<int, int, bool>
{
	/// points will be projected onto that plane
	int x, y;
	/// the points themselves; the () expects to get 2 indices into this array
	vector<Pnt3f> &point;

	lessByAngle( int xValue, int yValue, vector<Pnt3f> &pointVector )
	:	x(xValue), y(yValue), point(pointVector)
	{ }

	bool operator () ( int i1, int i2 ) const
	{
		const Pnt3f &p1 = point[i1];
		const Pnt3f &p2 = point[i2];

		if ( (p1[x] > 0.0) != (p2[x] > 0.0) )
		{
			if ( p1[x] > 0.0 )
				// p1 in 1. or 4. quadrant, p2 in 2. or 3. quadrant
				if ( p1[y] > 0.0 )
					// p1 in 1. quadrant
					return true; //-1;
				else
					// p1 in 4. quadrant
					return false; //+1;
			else
				// p1 in 2. or 3. quadrant, p2 in 1. or 4. quadrant
				if ( p2[y] > 0.0 )
					// p2 in 1. quadrant
					return false; //+1;
				else
					// p2 in 4. quadrant
					return true; //-1;
		}
		else
		{

			// both p1,p2 in 1.+4. quadrant or 2.+3. quadrant
			if ( (p1[y] > 0.0) != (p2[y] > 0.0) )
				// p1,p2 in different quadrants
				if ( p1[y] > 0.0 )
					// p1 in 1. or 2. quadrant => p2 in 3. or 4. quadrant
					return true; //-1;
				else
					// p1 in 3. or 4. quadrant => p2 in 1. or 2. quadrant
					return false; //+1;
			else
			{
				// p1, p2 in same quadrant
				if ( fabs(p1[x]) < NearZero )
					if ( fabs(p2[x]) < NearZero )
						// same angles
						return false; //0;
					else
						if ( p2[x] > 0.0 )
							// 1. or 4. quadrant
							if ( p1[y] > 0.0 )
								// 1. quadrant -> p1>p2
								return false; //+1;
							else
								// 4. quadrant -> p1<p2
								return true; //-1;
						else
							// 2. or 3.  quadrant
							if ( p1[y] > 0.0 )
								// 2. quadrant -> p1<p2
								return true; //-1;
							else
								// 3. quadrant -> p1>p2
								return false; //+1;

				if ( fabs(p2[x]) < NearZero )
					if ( p1[x] > 0.0 )
						// 1. or 4. quadrant
						if ( p2[y] > 0.0 )
							// 1. quadrant -> p1<p2
							return true; //-1;
						else
							// 4. quadrant -> p1>p2
							return false; //+1;
					else
						// 2. or 3.  quadrant
						if ( p2[y] > 0.0 )
							// 2. quadrant -> p1>p2
							return false; //+1;
						else
							// 3. quadrant -> p1<p2
							return true; //-1;

				float a = p1[y] / p1[x];
				float b = p2[y] / p2[x];
				if ( a > b + NearZero )
					return false; //+1;
				else
				if ( a < b - NearZero )
					return true; //-1;
				else
					return false; //0;
			}
		}
	}

};

COL_EXPORTIMPORT
osg::MFPnt3f* getPoints( const osg::NodePtr node );

COL_EXPORTIMPORT
osg::MFPnt3f* getPoints( const osg::GeometryPtr geo );
	
COL_EXPORTIMPORT
osg::GeoPositions3fPtr getPositions( const osg::NodePtr node );

COL_EXPORTIMPORT	
osg::GeometryPtr getGeom( const osg::NodePtr node );

COL_EXPORTIMPORT	
void dominantIndices( const Vec3f& v, unsigned int* x, unsigned int* y );

COL_EXPORTIMPORT	
void dominantIndices( const Vec3f& v,
					  unsigned int* x, unsigned int* y, unsigned int * z );

COL_EXPORTIMPORT	
unsigned int dominantIndex( const Vec3f& v );

COL_EXPORTIMPORT	
Pnt3f barycenter( const Pnt3f *points, const unsigned int npoints );

COL_EXPORTIMPORT	
Pnt3f barycenter( const vector<Pnt3f> &points );

COL_EXPORTIMPORT	
Pnt3f barycenter( const Pnt3f *points,
				  const unsigned int index[], const unsigned int nindices );

COL_EXPORTIMPORT	
Pnt3f barycenter( const osg::MFPnt3f *points,
				  const unsigned int index[], const unsigned int nindices );

COL_EXPORTIMPORT	
Pnt3f barycenter( const vector<Pnt3f> &points, const TopoFace &face );

COL_EXPORTIMPORT	
void sortVerticesCounterClockwise( const vector<Pnt3f> &vertex,
								   const Vec3f &normal,
								   TopoFace &face );

COL_EXPORTIMPORT	
osg::NodePtr geomFromPoints( const vector<Pnt3f> &vertex,
							 vector<TopoFace> &face,
							 int gl_type,
							 bool skip_redundant,
							 const Vec3f normals[] );

COL_EXPORTIMPORT	
osg::NodePtr geomFromPoints( const Pnt3f vertex[], unsigned int nvertices,
                             unsigned int face[],
                             const unsigned int face_nv[],
                             unsigned int nfaces,
                             int gl_type,
                             bool skip_redundant,
                             const Vec3f normals[] );

COL_EXPORTIMPORT	
osg::NodePtr makeCube( float radius, int gl_type );

COL_EXPORTIMPORT	
osg::Pnt3f lincomb( float c1, const osg::Pnt3f &pnt1, float c2, const osg::Pnt3f &pnt2 );

COL_EXPORTIMPORT	
void calcVertexNormals( const osg::NodePtr node, const float creaseAngle = 90 );

}//namespace col

#endif //ColUtilsOpenSG_H
